// EG4PlaHit.cc -- implementation of the class for plastic scintillators readout
// Created: Jan. 23, 2019, by Asia SUN, asia.rabbit@163.com
// Last Modified: Nov. 13, 2023 by Asia SUN

#include "EG4PlaSD.h"
#include "EG4PlaHit.h"
#include "G4SDManager.hh"
#include "G4HCofThisEvent.hh"
#include "G4Track.hh"
#include "G4Step.hh"
#include "G4VTouchable.hh"
#include "G4HCofThisEvent.hh"

EG4PlaSD::EG4PlaSD(const string &name) : G4VSensitiveDetector(name), fHC{nullptr}{
  collectionName.insert("PlaC");
  collectionName.insert("PlaC2"); // charged secondaries
  collectionName.insert("PlaC2N"); // secondary neutrons
  for(auto &i : fHCID) i = -1;
} // end ctor

EG4PlaSD::~EG4PlaSD(){}

void EG4PlaSD::Initialize(G4HCofThisEvent *hce){
  static auto sdm = G4SDManager::GetSDMpointer();
  for(int i = 0; i < kNHC; i++){
    fHC[i] = new EG4PlaHC(SensitiveDetectorName, collectionName[i]);
    if(fHCID[i] < 0) fHCID[i] = sdm->GetCollectionID(fHC[i]);
    hce->AddHitsCollection(fHCID[i], fHC[i]);
  } // end for over hit collections
} // end member function Iniitalize

bool EG4PlaSD::ProcessHits(G4Step *step, G4TouchableHistory *){
  // identify the particle and the track //
  G4Track *track = step->GetTrack();
  const G4ParticleDefinition *particle = track->GetParticleDefinition();
  const double charge = particle->GetPDGCharge();
  // parentID: 0: primary; >0: secondary; <0: postponed from previous ev
  // trackID: 1: primary; >1: secondaries
  const int pid = track->GetParentID(), tid = track->GetTrackID();
  const bool isPrimary = 0 == pid;
  int hcid = 2; // 2ndary neutron
  if(isPrimary) hcid = 0; // primary
  else if(charge) hcid = 1; // 2ndary charged
  const double de = step->GetTotalEnergyDeposit();

  // we only select the first hit in the det for a certain product //
  G4StepPoint *pp = step->GetPreStepPoint();
  const G4VTouchable *th = pp->GetTouchable();
  const int layerId = th->GetCopyNumber(1), stripId = th->GetCopyNumber(0);
  int ix = -1;
  EG4PlaHC *hc = fHC[hcid];
  for(int i = 0; i < int(hc->entries()); i++){
    if((*hc)[i]->GetLayerId() == layerId && (*hc)[i]->GetStripId() == stripId){
      (*hc)[i]->AddEdep(de);
      ix = i; break;
    } // end if
  } // end for
  if(-1 == ix){ // create a new hit and set it to the collection
    EG4PlaHit *hit = new EG4PlaHit();
    hit->SetHitType(hcid);
    hit->SetName(particle->GetParticleName());
    hit->SetParentId(pid);
    hit->SetTrackId(tid);
    hit->SetLayerId(layerId);
    hit->SetStripId(stripId);
    hit->SetLV(th->GetVolume()->GetLogicalVolume()); // for volume name and drawing
    hit->SetMass(particle->GetPDGMass() / CLHEP::amu_c2);
    hit->SetCharge(charge);
    hit->SetTime(pp->GetGlobalTime());
    hit->SetVelocity(pp->GetVelocity());
    hit->SetKineticEnergy(pp->GetKineticEnergy());
    hit->SetEdep(de);
    hit->SetTrkLen(track->GetTrackLength());
    hit->SetMomentum(pp->GetMomentum());
    auto transform = th->GetHistory()->GetTopTransform();
    transform.Invert();
    hit->SetRot(transform.NetRotation());
    hit->SetPos(transform.NetTranslation());
    hit->SetHitPos(pp->GetPosition());
    hc->insert(hit);
  } // end else

  return true;
} // end member function ProcessHits
